﻿namespace Holoville.HOTween.Plugins
{
    using Holoville.HOTween;
    using Holoville.HOTween.Core;
    using Holoville.HOTween.Plugins.Core;
    using System;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using UnityEngine;

    public class PlugVector3Path : ABSTweenPlugin
    {
        private float changePerc;
        private Vector3 diffChangeVal;
        private const float EPSILON = 0.001f;
        internal bool hasAdditionalStartingP;
        internal bool isClosedPath;
        private bool isPartialPath;
        private Holoville.HOTween.Axis lockPositionAxis;
        private Holoville.HOTween.Axis lockRotationAxis;
        private float lookAheadVal;
        private Vector3 lookPos;
        private Transform lookTrans;
        private const float MAX_LOOKAHED = 0.9999f;
        private const float MIN_LOOKAHEAD = 0.0001f;
        private Transform orientTrans;
        private OrientType orientType;
        internal Path path;
        internal float pathPerc;
        private Vector3[] points;
        private float startPerc;
        private const int SUBDIVISIONS_MULTIPLIER = 0x10;
        private Vector3 typedStartVal;
        private bool usesLocalPosition;
        internal static System.Type[] validPropTypes = new System.Type[] { typeof(Vector3) };
        internal static System.Type[] validValueTypes = new System.Type[] { typeof(Vector3[]) };

        public PlugVector3Path(Vector3[] p_path, PathType p_type = 1) : base(p_path, false)
        {
            this.lookAheadVal = 0.0001f;
            this.changePerc = 1f;
            this.pathType = p_type;
        }

        public PlugVector3Path(Vector3[] p_path, EaseType p_easeType, PathType p_type = 1) : base(p_path, p_easeType, false)
        {
            this.lookAheadVal = 0.0001f;
            this.changePerc = 1f;
            this.pathType = p_type;
        }

        public PlugVector3Path(Vector3[] p_path, bool p_isRelative, PathType p_type = 1) : base(p_path, p_isRelative)
        {
            this.lookAheadVal = 0.0001f;
            this.changePerc = 1f;
            this.pathType = p_type;
        }

        public PlugVector3Path(Vector3[] p_path, EaseType p_easeType, bool p_isRelative, PathType p_type = 1) : base(p_path, p_easeType, p_isRelative)
        {
            this.lookAheadVal = 0.0001f;
            this.changePerc = 1f;
            this.pathType = p_type;
        }

        public PlugVector3Path(Vector3[] p_path, AnimationCurve p_easeAnimCurve, bool p_isRelative, PathType p_type = 1) : base(p_path, p_easeAnimCurve, p_isRelative)
        {
            this.lookAheadVal = 0.0001f;
            this.changePerc = 1f;
            this.pathType = p_type;
        }

        public PlugVector3Path ClosePath()
        {
            return this.ClosePath(true);
        }

        public PlugVector3Path ClosePath(bool p_close)
        {
            this.isClosedPath = p_close;
            return this;
        }

        internal override void Complete()
        {
            if (this.isPartialPath)
            {
                this.DoUpdate(base._duration);
            }
            else
            {
                base.Complete();
            }
        }

        protected override void DoUpdate(float p_totElapsed)
        {
            int num;
            this.pathPerc = base.ease(p_totElapsed, this.startPerc, this.changePerc, base._duration, base.tweenObj.easeOvershootOrAmplitude, base.tweenObj.easePeriod);
            Vector3 vector = this.GetConstPointOnPath(this.pathPerc, true, this.path, out num);
            this.SetValue(vector);
            if (((this.orientType != OrientType.None) && (this.orientTrans != null)) && !this.orientTrans.Equals(null))
            {
                Transform transform = !this.usesLocalPosition ? null : this.orientTrans.parent;
                switch (this.orientType)
                {
                    case OrientType.ToPath:
                    {
                        Vector3 point;
                        if ((this.pathType != PathType.Linear) || (this.lookAheadVal > 0.0001f))
                        {
                            float t = this.pathPerc + this.lookAheadVal;
                            if (t > 1f)
                            {
                                t = !this.isClosedPath ? 1.000001f : (t - 1f);
                            }
                            point = this.path.GetPoint(t);
                        }
                        else
                        {
                            point = (vector + this.path.path[num]) - this.path.path[num - 1];
                        }
                        Vector3 up = this.orientTrans.up;
                        if (this.usesLocalPosition && (transform != null))
                        {
                            point = transform.TransformPoint(point);
                        }
                        if ((this.lockRotationAxis != Holoville.HOTween.Axis.None) && (this.orientTrans != null))
                        {
                            if ((this.lockRotationAxis & Holoville.HOTween.Axis.X) == Holoville.HOTween.Axis.X)
                            {
                                Vector3 position = this.orientTrans.InverseTransformPoint(point);
                                position.y = 0f;
                                point = this.orientTrans.TransformPoint(position);
                                up = (!this.usesLocalPosition || (transform == null)) ? Vector3.up : transform.up;
                            }
                            if ((this.lockRotationAxis & Holoville.HOTween.Axis.Y) == Holoville.HOTween.Axis.Y)
                            {
                                Vector3 vector5 = this.orientTrans.InverseTransformPoint(point);
                                if (vector5.z < 0f)
                                {
                                    vector5.z = -vector5.z;
                                }
                                vector5.x = 0f;
                                point = this.orientTrans.TransformPoint(vector5);
                            }
                            if ((this.lockRotationAxis & Holoville.HOTween.Axis.Z) == Holoville.HOTween.Axis.Z)
                            {
                                up = (!this.usesLocalPosition || (transform == null)) ? Vector3.up : transform.up;
                            }
                        }
                        this.orientTrans.LookAt(point, up);
                        return;
                    }
                    case OrientType.LookAtTransform:
                        if ((this.orientTrans != null) && !this.orientTrans.Equals(null))
                        {
                            this.orientTrans.LookAt(this.lookTrans.position, Vector3.up);
                        }
                        break;

                    case OrientType.LookAtPosition:
                        this.orientTrans.LookAt(this.lookPos, Vector3.up);
                        break;
                }
            }
        }

        internal Vector3 GetConstPointOnPath(float t)
        {
            int num;
            return this.GetConstPointOnPath(t, false, null, out num);
        }

        internal Vector3 GetConstPointOnPath(float t, bool p_updatePathPerc, Path p_path, out int out_waypointIndex)
        {
            if (p_updatePathPerc)
            {
                return p_path.GetConstPoint(t, out this.pathPerc, out out_waypointIndex);
            }
            out_waypointIndex = -1;
            return this.path.GetConstPoint(t);
        }

        protected override float GetSpeedBasedDuration(float p_speed)
        {
            return (this.path.pathLength / p_speed);
        }

        internal float GetWaypointsLengthPercentage(int p_pathWaypointId0, int p_pathWaypointId1)
        {
            if (this.pathType == PathType.Linear)
            {
                if (this.path.waypointsLength == null)
                {
                    this.path.StoreWaypointsLengths(0x10);
                }
                return (this.path.timesTable[p_pathWaypointId1] - this.path.timesTable[p_pathWaypointId0]);
            }
            if (this.path.waypointsLength == null)
            {
                this.path.StoreWaypointsLengths(0x10);
            }
            float num = 0f;
            for (int i = p_pathWaypointId0; i < p_pathWaypointId1; i++)
            {
                num += this.path.waypointsLength[i];
            }
            float num3 = num / this.path.pathLength;
            if (num3 > 1f)
            {
                num3 = 1f;
            }
            return num3;
        }

        internal override void Init(Tweener p_tweenObj, string p_propertyName, EaseType p_easeType, System.Type p_targetType, PropertyInfo p_propertyInfo, FieldInfo p_fieldInfo)
        {
            if (base.isRelative && p_tweenObj.isFrom)
            {
                base.isRelative = false;
                TweenWarning.Log(string.Concat(new object[] { "\"", p_tweenObj.target, ".", p_propertyName, "\": PlugVector3Path \"isRelative\" parameter is incompatible with HOTween.From. The tween will be treated as absolute." }));
            }
            this.usesLocalPosition = p_propertyName == "localPosition";
            base.Init(p_tweenObj, p_propertyName, p_easeType, p_targetType, p_propertyInfo, p_fieldInfo);
        }

        private bool IsWaypoint(Vector3 position, out int waypointIndex)
        {
            int length = this.path.path.Length;
            for (int i = 0; i < length; i++)
            {
                float num3 = this.path.path[i].x - position.x;
                float num4 = this.path.path[i].y - position.y;
                float num5 = this.path.path[i].z - position.z;
                if (num3 < 0f)
                {
                    num3 = 0f;
                }
                if (num4 < 0f)
                {
                    num4 = 0f;
                }
                if (num5 < 0f)
                {
                    num5 = 0f;
                }
                if (((num3 < 0.001f) && (num4 < 0.001f)) && (num5 < 0.001f))
                {
                    waypointIndex = i;
                    return true;
                }
            }
            waypointIndex = -1;
            return false;
        }

        public PlugVector3Path LockPosition(Holoville.HOTween.Axis p_lockAxis)
        {
            this.lockPositionAxis = p_lockAxis;
            return this;
        }

        public PlugVector3Path LookAt(Transform p_transform)
        {
            if (p_transform != null)
            {
                this.orientType = OrientType.LookAtTransform;
                this.lookTrans = p_transform;
            }
            return this;
        }

        public PlugVector3Path LookAt(Vector3 p_position)
        {
            this.orientType = OrientType.LookAtPosition;
            this.lookPos = p_position;
            this.lookTrans = null;
            return this;
        }

        public PlugVector3Path OrientToPath()
        {
            return this.OrientToPath(true);
        }

        public PlugVector3Path OrientToPath(Holoville.HOTween.Axis p_lockRotationAxis)
        {
            return this.OrientToPath(true, 0.0001f, p_lockRotationAxis);
        }

        public PlugVector3Path OrientToPath(bool p_orient)
        {
            return this.OrientToPath(p_orient, 0.0001f, Holoville.HOTween.Axis.None);
        }

        public PlugVector3Path OrientToPath(float p_lookAhead)
        {
            return this.OrientToPath(true, p_lookAhead, Holoville.HOTween.Axis.None);
        }

        public PlugVector3Path OrientToPath(float p_lookAhead, Holoville.HOTween.Axis p_lockRotationAxis)
        {
            return this.OrientToPath(true, p_lookAhead, p_lockRotationAxis);
        }

        public PlugVector3Path OrientToPath(bool p_orient, float p_lookAhead, Holoville.HOTween.Axis p_lockRotationAxis)
        {
            if (p_orient)
            {
                this.orientType = OrientType.ToPath;
            }
            this.lookAheadVal = p_lookAhead;
            if (this.lookAheadVal < 0.0001f)
            {
                this.lookAheadVal = 0.0001f;
            }
            else if (this.lookAheadVal > 0.9999f)
            {
                this.lookAheadVal = 0.9999f;
            }
            this.lockRotationAxis = p_lockRotationAxis;
            return this;
        }

        internal void ResetToFullPath(float p_duration, EaseType p_easeType)
        {
            this.isPartialPath = false;
            base._duration = p_duration;
            base.SetEase(p_easeType);
            this.startPerc = 0f;
            this.changePerc = 1f;
        }

        internal override void Rewind()
        {
            if (this.isPartialPath)
            {
                this.DoUpdate(0f);
            }
            else
            {
                base.Rewind();
            }
        }

        protected override void SetChangeVal()
        {
            Vector3[] vectorArray;
            if ((this.orientType != OrientType.None) && (this.orientTrans == null))
            {
                this.orientTrans = base.tweenObj.target as Transform;
            }
            int num = 1;
            int num2 = !this.isClosedPath ? 0 : 1;
            int length = this.points.Length;
            if (base.isRelative)
            {
                this.hasAdditionalStartingP = false;
                Vector3 vector = this.points[0] - this.typedStartVal;
                vectorArray = new Vector3[(length + 2) + num2];
                for (int i = 0; i < length; i++)
                {
                    vectorArray[i + num] = this.points[i] - vector;
                }
            }
            else
            {
                Vector3 vector2 = (Vector3) this.GetValue();
                Vector3 vector3 = vector2 - this.points[0];
                if (vector3.x < 0f)
                {
                    vector3.x = -vector3.x;
                }
                if (vector3.y < 0f)
                {
                    vector3.y = -vector3.y;
                }
                if (vector3.z < 0f)
                {
                    vector3.z = -vector3.z;
                }
                if (((vector3.x < 0.001f) && (vector3.y < 0.001f)) && (vector3.z < 0.001f))
                {
                    this.hasAdditionalStartingP = false;
                    vectorArray = new Vector3[(length + 2) + num2];
                }
                else
                {
                    this.hasAdditionalStartingP = true;
                    vectorArray = new Vector3[(length + 3) + num2];
                    if (base.tweenObj.isFrom)
                    {
                        vectorArray[vectorArray.Length - 2] = vector2;
                    }
                    else
                    {
                        vectorArray[1] = vector2;
                        num = 2;
                    }
                }
                for (int j = 0; j < length; j++)
                {
                    vectorArray[j + num] = this.points[j];
                }
            }
            length = vectorArray.Length;
            if (this.isClosedPath)
            {
                vectorArray[length - 2] = vectorArray[1];
            }
            if (this.isClosedPath)
            {
                vectorArray[0] = vectorArray[length - 3];
                vectorArray[length - 1] = vectorArray[2];
            }
            else
            {
                vectorArray[0] = vectorArray[1];
                Vector3 vector4 = vectorArray[length - 2];
                Vector3 vector5 = vector4 - vectorArray[length - 3];
                vectorArray[length - 1] = vector4 + vector5;
            }
            if (this.lockPositionAxis != Holoville.HOTween.Axis.None)
            {
                bool flag = (this.lockPositionAxis & Holoville.HOTween.Axis.X) == Holoville.HOTween.Axis.X;
                bool flag2 = (this.lockPositionAxis & Holoville.HOTween.Axis.Y) == Holoville.HOTween.Axis.Y;
                bool flag3 = (this.lockPositionAxis & Holoville.HOTween.Axis.Z) == Holoville.HOTween.Axis.Z;
                Vector3 typedStartVal = this.typedStartVal;
                for (int k = 0; k < length; k++)
                {
                    Vector3 vector7 = vectorArray[k];
                    vectorArray[k] = new Vector3(!flag ? vector7.x : typedStartVal.x, !flag2 ? vector7.y : typedStartVal.y, !flag3 ? vector7.z : typedStartVal.z);
                }
            }
            this.path = new Path(this.pathType, vectorArray);
            this.path.StoreTimeToLenTables(this.path.path.Length * 0x10);
            if (!this.isClosedPath)
            {
                this.diffChangeVal = vectorArray[length - 2] - vectorArray[1];
            }
        }

        protected override void SetIncremental(int p_diffIncr)
        {
            if (!this.isClosedPath)
            {
                Vector3[] path = this.path.path;
                int length = path.Length;
                for (int i = 0; i < length; i++)
                {
                    path[i] += this.diffChangeVal * p_diffIncr;
                }
                this.path.changed = true;
            }
        }

        internal void SwitchToPartialPath(float p_duration, EaseType p_easeType, float p_partialStartPerc, float p_partialChangePerc)
        {
            this.isPartialPath = true;
            base._duration = p_duration;
            base.SetEase(p_easeType);
            this.startPerc = p_partialStartPerc;
            this.changePerc = p_partialChangePerc;
        }

        protected override object endVal
        {
            get
            {
                return base._endVal;
            }
            set
            {
                if (base.tweenObj.isFrom)
                {
                    base._startVal = this.typedStartVal = (Vector3) value;
                }
                else
                {
                    base._endVal = value;
                    Vector3[] sourceArray = (Vector3[]) value;
                    this.points = new Vector3[sourceArray.Length];
                    Array.Copy(sourceArray, this.points, sourceArray.Length);
                }
            }
        }

        internal PathType pathType { get; private set; }

        protected override object startVal
        {
            get
            {
                return base._startVal;
            }
            set
            {
                if (base.tweenObj.isFrom)
                {
                    base._endVal = value;
                    Vector3[] sourceArray = (Vector3[]) value;
                    this.points = new Vector3[sourceArray.Length];
                    Array.Copy(sourceArray, this.points, sourceArray.Length);
                    Array.Reverse(this.points);
                }
                else
                {
                    base._startVal = this.typedStartVal = (Vector3) value;
                }
            }
        }

        private enum OrientType
        {
            None,
            ToPath,
            LookAtTransform,
            LookAtPosition
        }
    }
}

